/*
 * Na šachovnici P (obdelnikovou sit m * k) je pevně rozmístěno f bodů.
 * Úkolem je rozmístit dalších b-f bodů, tak aby byl maximální součet matice
 * Euklidovských vzdáleností všech dvojic bodů = sum_i_j d(i,j). Body se nesmějí
 * překrývat.
 *
 * Geometrická interpretace: rozmístit na ploše b bodů tak, aby byly co nejdál
 * od sebe.
 */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "main.h"
#include "mainCuda.h"

#define INPUT_FILE_PATH "./input.txt"

int hasFixedPoint_Host(Point point);
int pointEqual_Host(Point point1, Point point2);
/* unsigned long long int je zoufale málo pro tyto potřeby */

/* unsigned long long int combinations;
 unsigned long long int progress = 0;
 int percents = 0; */
/*
 * Hlavní funkce programu.
 */
int main() {
	FILE *inputFile;
	int i, j;
	int x = 0, y = 0;
	clock_t start, end;
	/* nulové buffery pro výstup --> pro ladění při segfaultech */
	setvbuf(stdout, NULL, _IONBF, 0);
	setvbuf(stderr, NULL, _IONBF, 0);

	printf("Vítejte v programu nenávist!\n");

	/* otevřeme soubor se vstupními daty */
	inputFile = fopen(INPUT_FILE_PATH, "r");
	if(inputFile == NULL){
		fprintf(stderr, "ERROR READING INPUT FILE %s\n", INPUT_FILE_PATH);
		return EXIT_FAILURE;
	}

	/* načteme vstupní data */
	loadInput(inputFile);

	/* validace vstupních dat */
	if(b > m * k){
		fprintf(stderr, "Je specifikováno více bodů, než se na plán může vejít (%d > %d*%d)\n", b, m, k);
		return EXIT_FAILURE;
	}
	if(b < f){
		fprintf(
				stderr,
				"Počet pevně umístěných bodů je větší než celkový počet bodů: (b < f, %d < %d). Nelze umístit záporný počet bodů.\n",
				b, f);
		return EXIT_FAILURE;
	}
	for(i = 0; i < f; i++){
		if(fixedPoints[i].x >= m || fixedPoints[i].y >= k){
			fprintf(stderr, "Jedna souřadnice je specifikována mimo plán ([%d, %d])\n", fixedPoints[i].x,
					fixedPoints[i].y);
			return EXIT_FAILURE;
		}
	}

	/* int N = m*k - f, K = b - f;
	 combinations = fact(N)/(fact(K)*fact(N - K)); */

	/* výpis vstupních dat */
	printf("Vstupní data: m = %d, k = %d, f = %d, b = %d.\n", m, k, f, b);
	for(i = 0; i < f; i++){
		printf("%d: [%d,%d] ", i, fixedPoints[i].x, fixedPoints[i].y);
	}
	printf("\n");
	/* printf("Počet kombinací: %d", combinations); */

	/*
	 * Alokace paměti
	 */
	variablePoints = (Point *)malloc((b - f) * sizeof(Point));
	possibilities = (Possibility **)malloc((b - f) * sizeof(Possibility *));
	for(i = 0; i < (b - f); i++){
		possibilities[i] = (Possibility *)malloc(9 * sizeof(Possibility));
	}

	for(i = 0; i < (b - f); i++){
		variablePoints[i].x = x;
		variablePoints[i].y = y;
		if(y < (m - 1)){
			y++;
		}
		else{
			x++;
			y = 0;
		}
		if(hasFixedPoint_Host(variablePoints[i])){
			i--;
		}
	}

	start = clock();
	/* Spuštění práce */
	doWork();

	end = clock();

	printf("Celkový čas: %f s\n", ((float) (end - start)) / CLOCKS_PER_SEC);
	printPlane();
	for(i = 0; i < (b - f); i++){
		printf("%d: [%d,%d] ", i, variablePoints[i].x, variablePoints[i].y);
	}
	printf("\n");

	return 0;
}

/*
 * Vypíše seznam možností.
 */
void printPossibilities(int index){
	int i;
	printf("Possibilities for point %d: [", index);
	for(i = 0; i < 9; i++){
		printf("[%d, %d]: %f", possibilities[index][i].point.x, possibilities[index][i].point.y, possibilities[index][i].value);
		if(i < 8){
			printf(", ");
		}
	}
	printf("]\n");
}

int hasFixedPoint_Host(Point point){
	int i, res = 0;
	for(i = 0; i < f; i++){
		if(pointEqual_Host(point, fixedPoints[i])){
			res = 1;
			break;
		}
	}
	return res;
}

int pointEqual_Host(Point point1, Point point2){
	return point1.x == point2.x && point1.y == point2.y;
}
